/**
 * Copyright (c) 快宝网络 kuaidihelp.com Co., Ltd. All Rights Reserved 禁止外泄以及用于其它的商业用途
 */

import React, { useCallback, useRef, useState, useEffect } from 'react';

// 检查标签名
function checkTagName(target: HTMLElement, name: string) {
  return `${name}`.split(',').includes(target.tagName.toLowerCase());
}

// 当前元素内部是否包含指定的元素
function isContains(current: HTMLElement | null, node_: HTMLElement | null) {
  let node = node_;
  while (node !== void 0 && node !== null && !checkTagName(node, 'body')) {
    if (node === current) {
      return true;
    }
    node = node.parentNode as HTMLElement;
  }
  return false;
}

// 查找符合条件的node
function getTargetNode(node: HTMLDivElement | null): HTMLDivElement | null {
  const { overflowX } = (node && node.style) || {};
  if (overflowX === 'scroll' || overflowX === 'auto') {
    return node;
  }
  const childNodes = node?.childNodes as NodeListOf<HTMLDivElement>;
  if (childNodes) {
    for (let i = 0, len = childNodes.length; i < len; i++) {
      const current = getTargetNode(childNodes[i]);
      if (current) {
        return current;
      }
    }
  }
  return null;
}

// 鼠标控制横向滚动处理组件
const MouseScroll: React.FC = (props) => {
  // 更新鼠标样式
  const [cursor, updateCursor] = useState('default');
  const dragRef = useRef<HTMLDivElement | null>(null);
  // 表格refer
  const tableRef = useRef<HTMLDivElement | null>(null);
  let startX = -1;

  // 先获取指定的node
  useEffect(() => {
    if (!tableRef.current) {
      tableRef.current = getTargetNode(dragRef.current);
    }
  }, [dragRef, tableRef]);

  // 监听鼠标事件
  const handleMouse = useCallback((e) => {
    const { type, pageX, target } = e;
    if (!isContains(dragRef.current, target)) {
      return;
    }
    e.stopPropagation();
    if (checkTagName(target, 'th')) {
      e.preventDefault();
    }
    switch (type) {
      case 'mousedown':
        if (!checkTagName(target, 'td,th')) {
          return;
        }
        startX = pageX;
        updateCursor('move');
        break;
      case 'mousemove':
        if (startX > -1 && tableRef.current) {
          tableRef.current.scrollLeft += startX - pageX;
          startX = pageX;
        }
        break;
      default:
        startX = -1;
        updateCursor('default');
        break;
    }
  }, []);
  return (
    <div
      style={{ cursor }}
      onMouseDown={handleMouse}
      onMouseMove={handleMouse}
      onMouseUp={handleMouse}
      onMouseLeave={handleMouse}
      ref={dragRef}
    >
      {props.children}
    </div>
  );
};

const DragTable: React.FC<any> = (props) => {
  return React.Children.map(props.children, (child) => {
    const { props: { scroll: { x: scrollX = 0 } = {} } = {} } = child as any;
    return scrollX ? <MouseScroll>{child}</MouseScroll> : child;
  });
};

export default DragTable;
